#include "socketbase.h"

SocketBase::SocketBase(QObject *parent) : QObject(parent)
{
    stateLabel = NULL;
    logTextEdit = NULL;

    socket = new QTcpSocket(this);
    connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this, SLOT(displayState(QAbstractSocket::SocketState)));
    connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(displayError(QAbstractSocket::SocketError)));
}

SocketBase::SocketBase(QString host, quint16 port, QObject *parent) : QObject(parent)
{
    this->host = host;
    this->port = port;

    stateLabel = NULL;
    logTextEdit = NULL;

    socket = new QTcpSocket(this);
    connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this, SLOT(displayState(QAbstractSocket::SocketState)));
    connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(displayError(QAbstractSocket::SocketError)));
    socket->connectToHost(host, port);
}

void SocketBase::setHost(QString host)
{
    this->host = host;
}
void SocketBase::setPort(quint16 port)
{
    this->port = port;
}

void SocketBase::connectToHost()
{
    socket->abort();
    socket->connectToHost(host, port);
}

void SocketBase::displayState(QAbstractSocket::SocketState state)
{
    if (stateLabel != NULL)
    {
        switch (state)
        {
            case QAbstractSocket::HostLookupState:
            case QAbstractSocket::ConnectingState:
                stateLabel->setText("connecting");
                break;
            case QAbstractSocket::ConnectedState:
                stateLabel->setText("connected");
                break;
            default:
                stateLabel->setText("disconnected");
                break;
        }
    }
}

void SocketBase::displayError(QAbstractSocket::SocketError error)
{
    if (logTextEdit != NULL)
    {
        switch (error)
        {
            case QAbstractSocket::RemoteHostClosedError:
                logTextEdit->append(tr("ERROR %1 %2: The remote host closed "
                                    "the connection.")
                                    .arg(toString(), QTime::currentTime().toString()));
                break;
            case QAbstractSocket::HostNotFoundError:
                logTextEdit->append(tr("ERROR %1 %2: The host address was not "
                                       "found.")
                                    .arg(toString(), QTime::currentTime().toString()));
                break;
            case QAbstractSocket::ConnectionRefusedError:
                logTextEdit->append(tr("ERROR %1 %2: The connection was refused "
                                       "by the peer (or timed out).")
                                    .arg(toString(), QTime::currentTime().toString()));
                break;
            default:
                logTextEdit->append(tr("ERROR %1 %2: The following error occurred: %3.")
                                     .arg(toString(), socket->errorString(), QTime::currentTime().toString()));

        }
    }
}

void SocketBase::setStateLabel(QLabel *stateLabel)
{
    this->stateLabel = stateLabel;
}
void SocketBase::setLogTextEdit(QTextEdit *logTextEdit)
{
    this->logTextEdit = logTextEdit;
}
QString SocketBase::getHost()
{
    return host;
}
quint16 SocketBase::getPort()
{
    return port;
}
QString SocketBase::toString()
{
    return tr("%1:%2").arg(host).arg(port);
}

#define BYTE_SWAP4(x) \
    (((x & 0xFF000000) >> 24) | \
     ((x & 0x00FF0000) >> 8)  | \
     ((x & 0x0000FF00) << 8)  | \
     ((x & 0x000000FF) << 24))

#define BYTE_SWAP2(x) \
    (((x & 0xFF00) >> 8) | \
     ((x & 0x00FF) << 8))

quint16 SocketBase::_htons(quint16 x) {
    if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
        return x;
    }
    else {
        return BYTE_SWAP2(x);
    }
}

quint16 SocketBase::_ntohs(quint16 x) {
    if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
        return x;
    }
    else {
        return BYTE_SWAP2(x);
    }
}

quint32 SocketBase::_htonl(quint32 x) {
    if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
        return x;
    }
    else {
        return BYTE_SWAP4(x);
    }
}

quint32 SocketBase::_ntohl(quint32 x) {
    if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
        return x;
    }
    else {
        return BYTE_SWAP4(x);
    }
}
